﻿using System;
using System.Collections.Generic;
using PreConditon = GX.DecisionTree.DTCondition;
namespace GX
{
    public enum BTNodeStatus
    {
        Idle,
        Run,
        Done,
    }
    public enum BTNodeResultType
    {
        Success = 1,
        Failed,
        Inerrupt,
    }
    public partial class BTTree
    {
        public abstract class BTNode
        {
            int _depth;
            PreConditon _preCondition;
            BTNodeStatus _status = BTNodeStatus.Idle;
            BTNodeResultType _resultType;
            string _message;

            Action<BTNode> onDone;
            BTNodeContainer _parent;
            public BTNodeContainer parent
            {
                get { return _parent; }
                internal set
                {
                    _parent = value;
                }
            }
            public BTNodeStatus status { get { return _status; } }
            public BTNodeResultType resultType { get { return _resultType; } }
            public string message { get { return _message; } }
            public bool isRunning { get { return _status == BTNodeStatus.Run; } }
            public bool isDone { get { return _status == BTNodeStatus.Done; } }
            public bool isSuccess { get { return this.isDone && _resultType == BTNodeResultType.Success; } }
            public bool isFailed { get { return this.isDone && _resultType == BTNodeResultType.Failed; } }
            public bool isInterrupt { get { return this.isDone && _resultType == BTNodeResultType.Inerrupt; } }
            public void SetPreCondition(PreConditon conditon)
            {
                _preCondition = conditon;
            }
            public bool Evaluate()
            {
                return (null == _preCondition || _preCondition.Evaluate())
                    && this.DoEvaluate();
            }
            public void Start(Action<BTNode> onDone, bool forceRestart = true)
            {
                if (_status == BTNodeStatus.Run)
                {
                    if (!forceRestart) return;
                    this.onDone = onDone;
                    OnEnter(true);
                }
                else
                {
                    if (_depth > 0)//在上一次的结束回调中启动：退出上一次
                    {
                        OnExit();
                    }

                    ++_depth;

                    this._status = BTNodeStatus.Run;
                    _resultType = BTNodeResultType.Success;
                    _message = null;
                    this.onDone = onDone;
                    OnEnter(false);
                }
            }
            void End(BTNodeResultType resultType, string message)
            {
                if (this._status != BTNodeStatus.Run) return;
                _status = BTNodeStatus.Done;
                _resultType = resultType;
                _message = message;
                if (null != onDone)
                {
                    var callback = onDone;
                    onDone = null;
                    callback(this);
                }
                --_depth;

                if (_status == BTNodeStatus.Done && _depth == 0)
                    OnExit();
            }
            protected void Finish(string message = null)
            {
                End(BTNodeResultType.Success, message);
            }
            protected void Fail()
            {
                End(BTNodeResultType.Success, message);
            }
            public void Stop(string message = null)
            {
                End(BTNodeResultType.Inerrupt, message);
            }
            virtual protected bool DoEvaluate()
            {
                return true;
            }
            virtual protected void OnEnter(bool isRestart)
            {

            }
            virtual protected void OnExit()
            {

            }
        }
        public abstract class BTNodeContainer : BTNode
        {
            List<BTNode> _children;
            public int numChildren { get { return null == _children ? 0 : _children.Count; } }
            public void AddChild(BTNode node)
            {
                if (node.parent == this || node == this) return;
                var p = this.parent;
                while (null != p)
                {
                    if (node == p)
                        return;
                    p = p.parent;
                }
                if (null == _children)
                    _children = new List<BTNode>();
                _children.Add(node);
                node.parent = this;
            }
            public void RemoveChild(BTNode node)
            {
                int index = GetChildIndex(node);
                if (index == -1) return;
                _children.RemoveAt(index);
                node.parent = null;
            }
            public void Clear()
            {
                if (null == _children) return;
                for (int i = 0; i < _children.Count; ++i)
                {
                    _children[i].parent = null;
                }
                _children.Clear();
            }
            public int GetChildIndex(BTNode node)
            {
                if (node.parent != this || null == _children) return -1;
                return _children.IndexOf(node);
            }
            public BTNode GetChildAt(int index)
            {
                return null == _children ? null : _children[index];
            }
            abstract protected void OnChildDone(BTNode node);
        }
    }
}
